package com.alm.handle.proxy.handler;


import com.alm.common.core.redis.RedisCache;
import com.alm.entity.PasingByteModel;
import com.alm.handle.service.SocketDataPasing;
import com.alm.handle.util.ContextManagerUtil;
import com.alm.handle.util.SoketEleKey;
import com.alm.util.ByteUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Component
@ChannelHandler.Sharable
public class ProxyServerChannelHandler extends ChannelInboundHandlerAdapter {
    @Autowired
    SocketDataPasing socketDataPasing;
    @Autowired
    RedisCache redisCache;
    private static final String PING = "p";
    private static final ByteBuf PONG = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("q\n".getBytes()));
    private static final AtomicInteger connect = new AtomicInteger();
    private int count = 0;//lostConnectCount

    private static final Logger logger = LoggerFactory.getLogger(ProxyServerChannelHandler.class);

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ContextManagerUtil.ctxMap.put(String.valueOf(ctx.hashCode()), ctx);
        connect.incrementAndGet();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        String ctxid=String.valueOf(ctx.hashCode());
        ByteBuf buf = (ByteBuf)msg;
        try {
            byte[] bytes=new byte[buf.readableBytes()];
            buf.readBytes(bytes);
            PasingByteModel byteModel;
            if(bytes.length<=3){
                byteModel=new PasingByteModel(bytes[0],
                        (byte) 0x00,(byte) 0x00);
            }else{
                byteModel=new PasingByteModel(bytes[0],
                        bytes[1],bytes[2]);
            }
            if(byteModel.isHeartbeat()){
                ctx.writeAndFlush(PONG.duplicate());//回复设备 心跳
                String devid=ContextManagerUtil.CHANNEL_DEV.get(ctxid);
                redisCache.setCacheObject(SoketEleKey.ON_LINE+devid.toUpperCase(),
                        "1",60, TimeUnit.SECONDS);
                return;
            }
            if(byteModel.isVisble()){ //字节还是字符
                PasingByteModel.Header header=new PasingByteModel.Header(byteModel);
                header.setDvcId(ByteUtils.getStringByByte(
                        ByteUtils.getByteByByte(6,12,bytes)//获取6个设备的字节
                        ,16).toUpperCase());//根据16进制将字节转为string
                header.setDvcType((int) ByteUtils.bytes2ShortBig(
                        ByteUtils.getByteByByte(12,14,bytes)
                ));//获取2个字节的设备类型
                header.setData(
                        ByteUtils.getStringByByteArr(
                                ByteUtils.getByteByByte(14,bytes.length+1,bytes))
                );//获取整个数据
                logger.info("data {}",ByteUtils.bytesToString(bytes));
                socketDataPasing.pasingData(header,ctxid);
                redisCache.setCacheObject(SoketEleKey.ON_LINE+header.getDvcId(),
                        "1",60, TimeUnit.SECONDS);
                ContextManagerUtil.CHANNEL_DEV.put(ctxid,header.getDvcId());
                ContextManagerUtil.DEV_CHANNEL.put(header.getDvcId(),ctxid);



            }
        }catch (Exception e){
           // e.printStackTrace();
            logger.info("read Exception {}", e.getMessage());
        }finally {
            ReferenceCountUtil.release(buf);
        }
    }


    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("channelInactive addr:{}, ctx: {}, total:{}", ctx.channel().remoteAddress(), ctx.hashCode(), connect.get());
        ContextManagerUtil.ctxMap.remove(String.valueOf(ctx.hashCode()));
        connect.decrementAndGet();
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        String ctxid=String.valueOf(ctx.hashCode());
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            switch (event.state()) {
                case READER_IDLE: //读空闲
                    count++;
                    logger.info("P 读空闲:{}, ctx:{}, count:{}", event.state(), ctx.hashCode(), count);
                    if (count > 4) {
                        ContextManagerUtil.ctxMap.remove(ctxid);
                        ctx.channel().close();
                        count = 0;
                    }
                    break;
                case WRITER_IDLE: //写空闲
                    count++;
                    logger.info("P 写空闲:{}, ctx:{}, count:{}", event.state(), ctx.hashCode(), count);
                    break;
                case ALL_IDLE: //读写空闲
                    count++;
                    logger.info("P event state:{}, 30s未收到客户端的心跳包, ctx:{}, count:{}, send q...", event.state(), ctx.hashCode(), count);
                    if (count > 4) {
                        logger.info("P close tcp channel, ctx:{}", ctx.hashCode());
                        ContextManagerUtil.ctxMap.remove(ctxid);
                        ctx.channel().close();
                        count = 0;
                    }
                default:
                    break;
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
